Skip to content

Conversation

brandonpayton
Copy link
Member

@brandonpayton brandonpayton commented Jul 17, 2025

Motivation for the change, related issues

In Playground CLI, /wordpress subdirs cannot currently be mounted before WP install because unzipping the WordPress zip fails. See #2381 for details.

Fixes #2381

Implementation details

The PR allows moving WordPress source files over an existing directory structure with some restrictions.

I'm a bit concerned it could lead to folks unintentionally overwriting their own files, so I'm not 100% we should land this. But let's discuss and find a path forward.

Testing Instructions (or ideally a Blueprint)

  • CI

@brandonpayton brandonpayton requested a review from a team July 17, 2025 21:53
@brandonpayton brandonpayton self-assigned this Jul 17, 2025
@brandonpayton brandonpayton added [Type] Bug An existing feature does not function as intended [Package][@wp-playground] CLI labels Jul 17, 2025
@brandonpayton brandonpayton marked this pull request as draft July 17, 2025 21:53
@mjangda
Copy link

mjangda commented Jul 18, 2025

Confirming that this PR fixes the issue I was having (trying to mount an existing database folder to allow persistence).

Comment on lines 533 to 576
const moveRecursively = (source: string, target: string, php: PHP) => {
if (php.fileExists(target)) {
/*
* Something exists at the target path.
* Let's check to make sure we aren't copying conflicting types.
*
* In this context, if the source path points to a file and the
* target path points to a directory, we do not intend for the file
* to be moved into the directory.
*/

if (!php.isDir(source) && php.isDir(target)) {
throw new Error(
`The target ${target} is a directory but the source ${source} is not. This is not supported.`
);
}
if (php.isDir(source) && !php.isDir(target)) {
throw new Error(
`The source ${source} is a directory but the target ${target} is not. This is not supported.`
);
}
}

if (isNonEmptyDir(target, php)) {
// We cannot move a directory over a non-empty directory,
// so we move the children one by one.
for (const file of php.listFiles(source)) {
const sourcePath = joinPaths(source, file);
const targetPath = joinPaths(target, file);
moveRecursively(sourcePath, targetPath, php);
}
} else {
php.mv(source, target);
}
php.rmdir(wpPath, { recursive: true });
} else {
php.mv(wpPath, php.documentRoot);
};
try {
moveRecursively(wpPath, php.documentRoot, php);
// Remove any directories left because there were existing dirs at the target path.
if (php.fileExists(wpPath)) {
php.rmdir(wpPath, { recursive: true });
}
} catch (e) {
throw e;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would fit nicely into FSHelpers, similarly to how we have copyRecursive.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And mount tests have a bunch of FS related tests, so they could be a good fit for adding tests.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brandonpayton
Copy link
Member Author

This unzip process may be replaced by @adamziel's Blueprints v2 work. I will test with that PR and see if the problem persists there.

@brandonpayton
Copy link
Member Author

This unzip process may be replaced by @adamziel's Blueprints v2 work. I will test with that PR and see if the problem persists there.

I tested with Blueprints V2 and encountered the following error:

"The target site root directory must be empty in the create-new-site mode, but it wasn't."

Let's take a look at what v2 Blueprint or CLI args would be good for this use case. Maybe mounting a dir before WP install is not the right thing to do.

Original note here.

@adamziel
Copy link
Collaborator

adamziel commented Jul 23, 2025

Let's still ship it as it fixes an important Blueprints v1 problem. We can address v2 as a follow-up. It's as much a technical question as it is a specification question, e.g. maybe requiring an empty directory for new site creation isn't a useful constraint.

const sourcePath = joinPaths(wpPath, file);
const targetPath = joinPaths(php.documentRoot, file);
php.mv(sourcePath, targetPath);
const moveRecursively = (source: string, target: string, php: PHP) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far, I've avoided moving this into FS helpers because it is an odd sort of operation:
Move a single directory, or if a directory already exists at the target path, move its children.

If there are existing files at the target paths, those files will be left intact, and the source files will not be moved. (But they will be deleted as leftovers of the unzipped WP dir later on.)

Comment on lines 566 to 576
if (php.fileExists(target) && !php.isDir(target)) {
// Refuse to overwrite existing files to avoid the chance of data loss.
const wpPath = source.replace(
/^\/tmp\/unzipped-wordpress\//,
'/'
);
logger.warn(
`Skipping ${wpPath} because a file exists at the target path.`
);
return;
}
Copy link
Member Author

@brandonpayton brandonpayton Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned that we might overwrite existing files. It is an mv-style operation, but the FSHelpers.mv() copies recursively if moving between different filesystems. And that can result in user data loss.

So we are skipping files that already exist.

@brandonpayton brandonpayton marked this pull request as ready for review July 24, 2025 04:43
@brandonpayton brandonpayton requested a review from a team July 24, 2025 04:47
@adamziel adamziel merged commit aa0cbd6 into trunk Jul 24, 2025
24 of 25 checks passed
@adamziel adamziel deleted the fix-unzip-wp-into-non-empty-directory branch July 24, 2025 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package][@wp-playground] CLI [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Playground CLI: /wordpress subdirs cannot be mounted before WP install
4 participants